package com.mrd.frame.redis;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;


@Component("redisClusterClient")
public class JedisClientClusterImpl {
	private static String redisCode = "utf-8";
	
	@Autowired
	RedisTemplate redisTemplate;

	/* ----------- common --------- */
	/**
	 * 根据表达式查询key
	 * @param pattern 索引
	 * @return Collection
	 */
	public Collection keys(String pattern) {
		return redisTemplate.keys(pattern);
	}

	/**
	 * 根据key删除缓存数据
	 * @author han
	 * @param key 索引
	 */
	public void delete(String key) {
		redisTemplate.delete(key);
	}

	/**
	 * 根据索引的集合删除数据
	 * @author han
	 * @param key 集合索引Collection
	 */
	public void delete(Collection key) {
		redisTemplate.delete(key);
	}

	/* ----------- string --------- */
	/**
	 * 根据key查询字符串
	 * @param key 索引关键字
	 * @param clazz 返回的对象
	 * @return
	 */
	public <T> T get(String key, Class clazz) {
		String value = (String) redisTemplate.opsForValue().get(key);
		return parseJson(value, clazz);
	}

	/**
	 * 根据多个查询索引查询
	 * @author han
	 * @param keys 多个索引集合
	 * @param clazz 返回的对象类型
	 * @return
	 */
	public List mget(Collection keys, Class clazz) {
		List values = redisTemplate.opsForValue().multiGet(keys);
		return parseJsonList(values, clazz);
	}

	/**
	 * 设置字符对象
	 * @param key 索引
	 * @param obj 值对象
	 * @param timeout 超时时间
	 * @param unit 时间单位
	 */
	public <T> void set(String key, T obj, Long timeout, TimeUnit unit) {
		if (obj == null) {
			return;
		}

		String value = toJson(obj);
		if (timeout != null) {
			redisTemplate.opsForValue().set(key, value, timeout, unit);
		} else {
			redisTemplate.opsForValue().set(key, value);
		}
	}

	/**
	 * 根据索引查询，并且更新对象
	 * @author han
	 * @param key 索引
	 * @param obj 入参对象
	 * @param clazz Class
	 * @return T 返回对象
	 */
	public <T> T getAndSet(String key, T obj, Class clazz) {
		if (obj == null) {
			return get(key, clazz);
		}

		String value = (String)redisTemplate.opsForValue().getAndSet(key, toJson(obj));
		return parseJson(value, clazz);
	}

	public int decrement(String key, int delta) {
		Long value = redisTemplate.opsForValue().increment(key, -delta);
		return value.intValue();
	}

	public int increment(String key, int delta) {
		Long value = redisTemplate.opsForValue().increment(key, delta);
		return value.intValue();
	}

	/* ----------- list --------- */
	public int size(String key) {
		return redisTemplate.opsForList().size(key).intValue();
	}

	public List range(String key, long start, long end, Class clazz) {
		List list = redisTemplate.opsForList().range(key, start, end);
		return parseJsonList(list, clazz);
	}

	public void rightPushAll(String key, Collection<?> values, Long timeout,
			TimeUnit unit) {
		if (values == null || values.isEmpty()) {
			return;
		}

		redisTemplate.opsForList().rightPushAll(key, toJsonList(values));
		if (timeout != null) {
			redisTemplate.expire(key, timeout, unit);
		}
	}

	public <T> void leftPush(String key, T obj) {
		if (obj == null) {
			return;
		}

		redisTemplate.opsForList().leftPush(key, toJson(obj));
	}

	public <T> T leftPop(String key, Class clazz) {
		String value = (String)redisTemplate.opsForList().leftPop(key);
		return parseJson(value, clazz);
	}

	public void remove(String key, int count, Object obj) {
		if (obj == null) {
			return;
		}

		redisTemplate.opsForList().remove(key, count, toJson(obj));
	}

	/* ----------- zset --------- */
	public int zcard(String key) {
		return redisTemplate.opsForZSet().zCard(key).intValue();
	}

	public List zrange(String key, long start, long end, Class clazz) {
		Set set = redisTemplate.opsForZSet().range(key, start, end);
		return parseJsonList(setToList(set), clazz);
	}

	private List setToList(Set set) {
		if (set == null) {
			return null;
		}
		return new ArrayList(set);
	}

	public void zadd(String key, Object obj, double score) {
		if (obj == null) {
			return;
		}
		redisTemplate.opsForZSet().add(key, toJson(obj), score);
	}

	public void zrem(String key, Object obj) {
		if (obj == null) {
			return;
		}
		redisTemplate.opsForZSet().remove(key, toJson(obj));
	}

	public void unionStore(String destKey, Collection keys, Long timeout,
			TimeUnit unit) {
		if (keys == null || keys.isEmpty()) {
			return;
		}

		Object[] keyArr = keys.toArray();
		String key = (String) keyArr[0];

		Collection otherKeys = new ArrayList(keys.size() - 1);
		for (int i = 1; i < keyArr.length; i++) {
			otherKeys.add((String) keyArr[i]);
		}

		redisTemplate.opsForZSet().unionAndStore(key, otherKeys, destKey);
		if (timeout != null) {
			redisTemplate.expire(destKey, timeout, unit);
		}
	}

	/* ----------- tool methods --------- */
	public String toJson(Object obj) {
		return JSON.toJSONString(obj, SerializerFeature.SortField);
	}

	public <T> T parseJson(String json, Class clazz) {
		return (T)JSON.parseObject(json, clazz);
	}

	public List toJsonList(Collection<?> values) {
		if (values == null) {
			return null;
		}
		List result = new ArrayList();
		for (Object obj : values) {
			result.add(toJson(obj));
		}
		return result;
	}

	public List parseJsonList(List<String> list, Class clazz) {
		if (list == null) {
			return null;
		}
		List result = new ArrayList();
		for (String s : list) {
			result.add(parseJson(s, clazz));
		}
		return result;
	}
}
